#include "global.h"
#include "screen_font.h"
#include "ili9320.h"




#if (USE_LCD == 1)
#define LCD_BACKLIGHT_CLK   RCC_APB2Periph_GPIOD
#define LCD_BACKLIGHT_PORT  GPIOD
#define LCD_BACKLIGHT_PIN   GPIO_Pin_13

#define LCD_BACKLIGHT_ON()  GPIO_SetBits(LCD_BACKLIGHT_PORT, LCD_BACKLIGHT_PIN)
#define LCD_BACKLIGHT_OFF() GPIO_ResetBits(LCD_BACKLIGHT_PORT, LCD_BACKLIGHT_PIN)

#define Bank1_LCD_D	        ((uint32_t)0x60020000)	/* disp Data ADDR */
#define Bank1_LCD_C         ((uint32_t)0x60000000)	/* disp Reg  ADDR */

#define LCD_RST_CLK         RCC_APB2Periph_GPIOE
#define LCD_RST_PORT        GPIOE
#define LCD_RST_PIN         GPIO_Pin_1
#define LCD_RESET_LOW()     GPIO_ResetBits(LCD_RST_PORT, LCD_RST_PIN)
#define LCD_RESET_HIGH()    GPIO_SetBits(LCD_RST_PORT, LCD_RST_PIN)

// PD14-D0, PD15-D1, PD0-D2,   PD1-D3,   PE7-D4,   PE8-D5,  PE9-D6, PE10-D7,
// PE11-D8, PE12-D9, PE13-D10, PE14-D11, PE15-D12, PD8-D13, PD9-D14, PD10-D15
#define LCD_DATA_D_PORT     GPIOD
#define LCD_DATA_D_PINS     (GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_14 | GPIO_Pin_15)
#define LCD_DATA_E_PORT     GPIOE
#define LCD_DATA_E_PINS     (GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15)
// PD11-RS (A16), PD4-nOE, PD5-nWE, PD7-LCD-CS
#define LCD_CTRL_PORT       GPIOD
#define LCD_CTRL_PINS       GPIO_Pin_11 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7
#endif



/****************************************************************************
*
****************************************************************************/
void LCD_Delay(__IO uint32_t nCount)
{
    for (; nCount != 0; nCount--)
    {
        __NOP();
    }
}

/****************************************************************************
*ili9320写命令
****************************************************************************/
void LCD_WR_CMD(uint32_t index, uint32_t val)
{
    *(__IO uint16_t*) (Bank1_LCD_C) = index;
    *(__IO uint16_t*) (Bank1_LCD_D) = val;
}

/****************************************************************************
* @brief  Reads the selected LCD Register.
* @param  LCD_Reg: address of the selected register.
* @retval LCD Register Value.
****************************************************************************/
uint16_t LCD_RD_CMD(uint8_t index)
{
    *(__IO uint16_t*) (Bank1_LCD_C) = index;    /* Write 16-bit Index (then Read Reg) */
    return *(__IO uint16_t*) (Bank1_LCD_D);     /* Read 16-bit Reg */
}

/****************************************************************************
 *ili9320芯片在stm32上相关硬件接口配置
 ****************************************************************************/
void LCD_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    FSMC_NORSRAMTimingInitTypeDef  NORSRAMTiming;
    FSMC_NORSRAMInitTypeDef NORSRAMInit;

    RCC_APB2PeriphClockCmd(LCD_RST_CLK | LCD_BACKLIGHT_CLK, ENABLE);

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

    GPIO_InitStructure.GPIO_Pin = LCD_RST_PIN;
    GPIO_Init(LCD_RST_PORT, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = LCD_BACKLIGHT_PIN;
    GPIO_Init(LCD_BACKLIGHT_PORT, &GPIO_InitStructure);

    //------------------------- FSMC pins
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

    GPIO_InitStructure.GPIO_Pin = LCD_DATA_D_PINS;
    GPIO_Init(LCD_DATA_D_PORT, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = LCD_DATA_E_PINS;
    GPIO_Init(LCD_DATA_E_PORT, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = LCD_CTRL_PINS;
    GPIO_Init(LCD_CTRL_PORT, &GPIO_InitStructure);


    //------------------------- FSMC controller
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE);

    NORSRAMTiming.FSMC_AddressSetupTime = 0x02;
    NORSRAMTiming.FSMC_AddressHoldTime = 0x01;
    NORSRAMTiming.FSMC_DataSetupTime = 0x05;
    NORSRAMTiming.FSMC_BusTurnAroundDuration = 0x00;
    NORSRAMTiming.FSMC_CLKDivision = 0x01;
    NORSRAMTiming.FSMC_DataLatency = 0x00;
    NORSRAMTiming.FSMC_AccessMode = FSMC_AccessMode_B;

    NORSRAMInit.FSMC_Bank = FSMC_Bank1_NORSRAM1;
    NORSRAMInit.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;
    NORSRAMInit.FSMC_MemoryType = FSMC_MemoryType_NOR;
    NORSRAMInit.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;
    NORSRAMInit.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;
    NORSRAMInit.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;
    NORSRAMInit.FSMC_WrapMode = FSMC_WrapMode_Disable;
    NORSRAMInit.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
    NORSRAMInit.FSMC_WriteOperation = FSMC_WriteOperation_Enable;
    NORSRAMInit.FSMC_WaitSignal = FSMC_WaitSignal_Disable;
    NORSRAMInit.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;
    NORSRAMInit.FSMC_WriteBurst = FSMC_WriteBurst_Disable;
    NORSRAMInit.FSMC_ReadWriteTimingStruct = &NORSRAMTiming;
    NORSRAMInit.FSMC_WriteTimingStruct = &NORSRAMTiming;
    FSMC_NORSRAMInit(&NORSRAMInit);

    FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM1, ENABLE);
}

/****************************************************************************
 *ili9320初始化配置
 ****************************************************************************/
void LCD_Initialization()
{
    LCD_RESET_LOW();
    LCD_Delay(0xAFFF);
    LCD_RESET_HIGH();
    LCD_Delay(0xAFFF);

    LCD_WR_CMD(0x00E3, 0x3008); // Set internal timing
    LCD_WR_CMD(0x00E7, 0x0012); // Set internal timing
    LCD_WR_CMD(0x00EF, 0x1231); // Set internal timing
    LCD_WR_CMD(0x0000, 0x0001); // Start Oscillation
    LCD_WR_CMD(0x0001, 0x0100); // set SS and SM bit
    LCD_WR_CMD(0x0002, 0x0700); // set 1 line inversion

    LCD_WR_CMD(0x0003, 0x1130); // set GRAM write direction and BGR=0,262K colors,1 transfers/pixel. 0x1030
    LCD_WR_CMD(0x0004, 0x0000); // Resize register
    LCD_WR_CMD(0x0008, 0x0202); // set the back porch and front porch
    LCD_WR_CMD(0x0009, 0x0000); // set non-display area refresh cycle ISC[3:0]
    LCD_WR_CMD(0x000A, 0x0000); // FMARK function
    LCD_WR_CMD(0x000C, 0x0000); // RGB interface setting
    LCD_WR_CMD(0x000D, 0x0000); // Frame marker Position
    LCD_WR_CMD(0x000F, 0x0000); // RGB interface polarity

    //Power On sequence
    LCD_WR_CMD(0x0010, 0x0000); // SAP, BT[3:0], AP, DSTB, SLP, STB
    LCD_WR_CMD(0x0011, 0x0007); // DC1[2:0], DC0[2:0], VC[2:0]
    LCD_WR_CMD(0x0012, 0x0000); // VREG1OUT voltage
    LCD_WR_CMD(0x0013, 0x0000); // VDV[4:0] for VCOM amplitude

    LCD_Delay(200); // Dis-charge capacitor power voltage

    LCD_WR_CMD(0x0010, 0x1690); // SAP, BT[3:0], AP, DSTB, SLP, STB
    LCD_WR_CMD(0x0011, 0x0227); // R11h=0x0221 at VCI=3.3V, DC1[2:0], DC0[2:0], VC[2:0]
    LCD_Delay(50); // Delay 50ms
    LCD_WR_CMD(0x0012, 0x001C); // External reference voltage= Vci;
    LCD_Delay(50); // Delay 50ms
    LCD_WR_CMD(0x0013, 0x1800); // R13=1200 when R12=009D;VDV[4:0] for VCOM amplitude
    LCD_WR_CMD(0x0029, 0x001C); // R29=000C when R12=009D;VCM[5:0] for VCOMH
    LCD_WR_CMD(0x002B, 0x000D); // Frame Rate = 91Hz
    LCD_Delay(50); // Delay 50ms
    LCD_WR_CMD(0x0020, 0x0000); // GRAM horizontal Address
    LCD_WR_CMD(0x0021, 0x0000); // GRAM Vertical Address

    // ----------- Adjust the Gamma Curve ----------//
    LCD_WR_CMD(0x0030, 0x0007);
    LCD_WR_CMD(0x0031, 0x0302);
    LCD_WR_CMD(0x0032, 0x0105);
    LCD_WR_CMD(0x0035, 0x0206);
    LCD_WR_CMD(0x0036, 0x0808);
    LCD_WR_CMD(0x0037, 0x0206);
    LCD_WR_CMD(0x0038, 0x0504);
    LCD_WR_CMD(0x0039, 0x0007);
    LCD_WR_CMD(0x003C, 0x0105);
    LCD_WR_CMD(0x003D, 0x0808);

    //------------------ Set GRAM area ---------------//
    LCD_WR_CMD(0x0050, 0x0000); // Horizontal GRAM Start Address
    LCD_WR_CMD(0x0051, 0x00EF); // Horizontal GRAM End Address
    LCD_WR_CMD(0x0052, 0x0000); // Vertical GRAM Start Address
    LCD_WR_CMD(0x0053, 0x013F); // Vertical GRAM Start Address
    LCD_WR_CMD(0x0060, 0xA700); // Gate Scan Line
    LCD_WR_CMD(0x0061, 0x0001); // NDL,VLE, REV
    LCD_WR_CMD(0x006A, 0x0000); // set scrolling line

    //-------------- Partial Display Control ---------//
    LCD_WR_CMD(0x0080, 0x0000);
    LCD_WR_CMD(0x0081, 0x0000);
    LCD_WR_CMD(0x0082, 0x0000);
    LCD_WR_CMD(0x0083, 0x0000);
    LCD_WR_CMD(0x0084, 0x0000);
    LCD_WR_CMD(0x0085, 0x0000);

    //-------------- Panel Control -------------------//
    LCD_WR_CMD(0x0090, 0x0010);
    LCD_WR_CMD(0x0092, 0x0000);
    LCD_WR_CMD(0x0093, 0x0003);
    LCD_WR_CMD(0x0095, 0x0110);
    LCD_WR_CMD(0x0097, 0x0000);
    LCD_WR_CMD(0x0098, 0x0000);
    LCD_WR_CMD(0x0007, 0x0133); // 262K color and display ON

    LCD_WR_CMD(32, 0);
    LCD_WR_CMD(33, LCD_WIDTH - 1);
    *(__IO uint16_t*) (Bank1_LCD_C) = 34;

    for (int n = 0; n < (LCD_HEIGHT * LCD_WIDTH); n++)
    {
        *(__IO uint16_t*) (Bank1_LCD_D) = 0xF17F;
    }
}



/****************************************************************************
* @brief  Get the ILI9320 ID.
* @param  None
* @retval The ILI9320 ID
****************************************************************************/
uint16_t LCD_ReadID(void)
{
    return (LCD_RD_CMD(0x00));
}



/****************************************************************************
*设置当前聚焦位置
****************************************************************************/
void LCD_SetCursor(uint16_t x, uint16_t y)
{
    *(__IO uint16_t*) (Bank1_LCD_C) = 32;
    *(__IO uint16_t*) (Bank1_LCD_D) = y;

    *(__IO uint16_t*) (Bank1_LCD_C) = 33;
    *(__IO uint16_t*) (Bank1_LCD_D) = LCD_WIDTH - 1 - x;
}


/****************************************************************************
 *ili9320清屏
 ****************************************************************************/
void LCD_Clear(uint16_t dat)
{
    uint32_t i;
    *(__IO uint16_t*) (Bank1_LCD_C) = 0x50;
    *(__IO uint16_t*) (Bank1_LCD_D) = 0;

    *(__IO uint16_t*) (Bank1_LCD_C) = 0x51;
    *(__IO uint16_t*) (Bank1_LCD_D) = LCD_HEIGHT - 1;

    *(__IO uint16_t*) (Bank1_LCD_C) = 0x52;
    *(__IO uint16_t*) (Bank1_LCD_D) = 0;

    *(__IO uint16_t*) (Bank1_LCD_C) = 0x53;
    *(__IO uint16_t*) (Bank1_LCD_D) = LCD_WIDTH - 1;

    *(__IO uint16_t*) (Bank1_LCD_C) = 32;
    *(__IO uint16_t*) (Bank1_LCD_D) = 0;
    *(__IO uint16_t*) (Bank1_LCD_C) = 33;
    *(__IO uint16_t*) (Bank1_LCD_D) = 0;

    *(__IO uint16_t*) (Bank1_LCD_C) = 34;
    for (i = 0; i < (LCD_HEIGHT * LCD_WIDTH); i++)
        * (__IO uint16_t*) (Bank1_LCD_D) = dat;
}

/**
* @brief  Sets a display window
* @param  Xpos:   specifies the X bottom left position.
* @param  Ypos:   specifies the Y bottom left position.
* @param  Height: display window height.
* @param  Width:  display window width.
* @retval None
*/
void LCD_SetDisplayWindow(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height)
{
    LCD_WR_CMD(0x50, (Ypos));/* Horizontal GRAM Start Address */
    LCD_WR_CMD(0x51, (Ypos + Height - 1));/* Horizontal GRAM End Address */

    LCD_WR_CMD(0x52, LCD_WIDTH - Xpos - Width);/* Vertical GRAM Start Address */
    LCD_WR_CMD(0x53, LCD_WIDTH - Xpos - 1);/* Vertical GRAM End Address */
}

/****************************************************************************
 *画点函数
 ****************************************************************************/
void LCD_SetPoint(uint16_t x, uint16_t y, uint16_t point)
{
    if ((y >= LCD_HEIGHT) || (x >= LCD_WIDTH)) return;
    *(__IO uint16_t*) (Bank1_LCD_C) = 32;
    *(__IO uint16_t*) (Bank1_LCD_D) = y;

    *(__IO uint16_t*) (Bank1_LCD_C) = 33;
    *(__IO uint16_t*) (Bank1_LCD_D) = (LCD_WIDTH - 1) - x;

    *(__IO uint16_t*) (Bank1_LCD_C) = 34;
    *(__IO uint16_t*) (Bank1_LCD_D) = point;
}

/****************************************************************************
* @brief  Read pixel.
* @param  None
* @retval the RGB pixel color
****************************************************************************/
uint16_t LCD_GetPoint(uint16_t Xpos, uint16_t Ypos)
{
    LCD_SetCursor(Xpos, Ypos);    /* Set Cursor */
    return LCD_RD_CMD(0x22);    /* Read 16-bit Reg */
}

/****************************************************************************
 *画一条垂直的线
 ****************************************************************************/
void LCD_VLine(uint16_t x0, uint16_t y0, uint16_t h, uint16_t color)
{
    int i;
    LCD_SetCursor(x0, y0);
    *(__IO uint16_t*) (Bank1_LCD_C) = 0x22;
    for (i = 0; i < h; i++)
    {
        *(__IO uint16_t*) (Bank1_LCD_D) = color;
    }
}

/****************************************************************************
 *
 ****************************************************************************/
void LCD_PutChar(uint16_t x, uint16_t y, uint8_t c, uint16_t charColor, uint16_t bkColor)
{
    uint16_t i, j;
    uint8_t data;
    uint8_t mask;
    const uint8_t* datas = &ascii_8x16[((c - ' ') * FONT_STEP_Y)];    //&ascii_8x16[((c - ' ') * FONT_STEP_Y)];

    for (i = 0; i < FONT_STEP_Y; i++)
    {
        data = *datas++;
        mask = 0x80;
#if (FONT_WIDTH == 8)
        while (mask != 0)
        {
            LCD_SetPoint(x + j, y + i, (data & mask ? charColor : bkColor));
            mask >>= 1;
        }
#else
        for (j = 0; j < FONT_STEP_X; j++)
        {
            LCD_SetPoint(x + j, y + i, (data & mask ? charColor : bkColor));
            mask >>= 1;
        }
#endif
    }
}

/****************************************************************************
 *ili9320背光开关
 ****************************************************************************/
void LCD_BackLight(uint8_t status)
{
    if (status >= 1)
    {
        LCD_BACKLIGHT_ON();
    }
    else
    {
        LCD_BACKLIGHT_OFF();
    }
}

